package org.wzy.design.patterns.proxy.custom;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

/**
 * ClassName: GPProxy <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: 自定义Proxy实现，生成代理对象的代码. <br/>
 * date: 2017年6月15日 上午12:00:02 <br/>
 * 
 * @author wzy_h
 * @version
 * @since JDK 1.8
 */
public class GPProxy {

	private final static String ln = "\n";

	// 该方法复制于Proxy类下的同名方法
	@SuppressWarnings({"rawtypes", "unchecked"})
	public static Object newProxyInstance(GPClassLoader loader, Class<?>[] interfaces, GPInvocationHandler h) {
		// 1.生成源代码
		String proxySrc = generateSrc(interfaces[0]);

		// 2.将生成的源码输出到磁盘，保存为*.java文件
		try {
			String filePath = GPProxy.class.getResource("").getPath();
			File f = new File(filePath + "$Proxy0.java");
			FileWriter fw = new FileWriter(f);
			fw.write(proxySrc);
			fw.flush();
			fw.close();


			// 3.编译源码，并且生成.class文件
			JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
			StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null, null, null);
			Iterable it = manager.getJavaFileObjects(f);

			CompilationTask task = javaCompiler.getTask(null, manager, null, null, null, it);
			task.call();
			manager.close();
			// 4.将class文件中的内容动态加载到JVM中

			// 5.返回被代理后的代理对象

			Class clz = loader.findClass("$Proxy0");
			Constructor c = clz.getConstructor(GPInvocationHandler.class);
			return c.newInstance(h);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private static String generateSrc(Class<?> interfaces) {
		StringBuffer src = new StringBuffer();
		src.append("package com.gupao.vip.proxy.custom;" + ln);
		src.append("import java.lang.reflect.Method;" + ln);
		src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
		src.append("GPInvocationHandler h;" + ln);

		src.append("public $Proxy0(GPInvocationHandler h) {" + ln);
		src.append("this.h = h;" + ln);
		src.append("}" + ln);

		for (Method m : interfaces.getMethods()) {
			src.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
			src.append("try{" + ln);
			src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" + m.getName()
				+ "\", new Class[]{});" + ln);
			src.append("this.h.invoke(this, m, null);" + ln);
			src.append("}catch(Exception e) {" + ln);
			src.append("e.printStackTrace();" + ln);
			src.append("}" + ln);
			src.append("}" + ln);
		}

		src.append("}");

		return src.toString();
	}
}
